const dayjs = require('dayjs');
const router = require('koa-router')();

const { httpClient } = require('../../libs/index');
const { getDbHelper } = require('../../libs/DbHelpers');

const scripts = require('./scripts/shares');

const requestOptions = {
  headers: {
    'Referer': 'http://qt.gtimg.cn',
    'content-type': 'application/javascript;charset=gbk'
  }
};

let expireTimes = 0;
const xueQiuRequestOptions = {
  headers: {
    Referer: 'https://xueqiu.com/hq',
    Cookie: ''
  },
  timeout: 15000
};

router.prefix('/api/shares', '股票相关接口');

// 添加关注的股票
router.post('/save', async (ctx, next) => {
  let rs = await getDbHelper(0).execute(scripts.SaveShare, ctx.request.body);

  ctx.body = rs;
});

router.get('/index', async (ctx, next) => {
  let sh = getShareIndex('s_sh000001', '上证指数');
  let sz = getShareIndex('s_sz399001', '深圳成指');
  let cy = getShareIndex('s_sz399006', '创业板指');

  let rs = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    datas: []
  };

  await Promise.all([sh, sz, cy]).then(values => {
    rs.datas = values;

    ctx.body = rs;
  }).catch(err => {
    rs.success = false;
    rs.message = err.message;

    ctx.body = rs;
  });
}, '获取指数信息');

router.post('/index/save', async (ctx, next) => {
  let rs = await collectIndexes();

  ctx.body = rs;
}, {
  desc: '保存指数信息',
  body: {
    name: { type: 'string', desc: '指数名称' },
    recordDateTime: { type: 'string', desc: '记录时间' },
    index: { type: 'number', desc: '指数值' },
    changes: { type: 'number', desc: '变化值' },
    changeRatio: { type: 'number', desc: '变化比例' },
    turnoverVolume: { type: 'number', desc: '交易量' }
  }
});

router.get('/index/statistics', async (ctx, next) => {
  let rs = await getDbHelper(0).queryForList(scripts.GetIndexes);

  ctx.body = rs;
}, '获取股票指数监控数据');

// 关注的股票列表
router.get('/list', async (ctx, next) => {
  let data = await getDbHelper(0).queryForList(scripts.GetSharesWithPrice);

  ctx.body = data;
});

// 单支股票价格信息
router.get('/:code/prices', async (ctx, next) => {
  let code = ctx.params.code;
  let rs = await getDbHelper(0).queryForList(scripts.GetSharePriceDetail, { code: code })

  if (rs.datas.length == 0) {

  }

  ctx.body = rs;
}, '获取关注的股票列表');

// 单支股票数据分析
router.get('/:code/statistics', async (ctx, next) => {
  let code = ctx.params.code;
  let rs = await getDbHelper(0).queryForList(scripts.GetCurrentDateStatistics, { code: code, interval: 5 })

  if (rs.datas.length == 0) {
    let datas = await getChartDatas(code);

    rs.datas = (datas.data.items || []).map(d => {
      let date = dayjs(d.timestamp);

      return {
        Date: date.format('YYYY-MM-DD'),
        Time: date.format('HH:mm:ss'),
        CurrentPrice: d.current + d.chg,
        YesterdayPrice: d.current
      }
    });
  }

  ctx.body = rs;
});

// 删除关注的股票
router.delete('/remove/:code', async (ctx, next) => {
  let code = ctx.params.code;

  let rs = await getDbHelper(0).execute(scripts.RemoveShare, { code: code })

  ctx.body = rs;
});

// 清理历史数据
router.get('/clear', async (ctx, next) => {
  let rs = await getDbHelper(0).execute(scripts.ClearSharesDailyDatas);

  ctx.body = rs;
});

// 获取股票分析数据
router.get('/statistics', async (ctx, next) => {
  let tasks = [];
  let shares = await getDbHelper(0).queryForList(scripts.GetShares);

  for (let data of (shares.datas || [])) {
    tasks.push(getDbHelper(0).queryForList(scripts.GetStatistics, { code: data.Code, interval: 300 }));
  }

  let rs = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    details: []
  };

  await Promise.all(tasks).then(values => {
    let index = 0;
    values.forEach(v => {
      let data = shares.datas[index];
      let detail = {
        code: data.Code,
        name: data.Name,
        datas: v.datas
      };

      rs.details.push(detail);

      index++;
    });

    ctx.body = rs;
  }).catch(err => {
    ctx.body = err
  });
});

/**
 * 收集股票信息
 */
router.get('/collect', async (ctx, next) => {
  await collectDatas();

  ctx.body = {
    at: dayjs().format("YYYY-MM-DD HH:mm:ss"),
    success: true
  };
});

// 公司信息
router.get('/:code/company', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/f10/cn/company.json?symbol=${code}`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: { company: null } };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data.company
  };
});

// 股票价格
router.get('/:code/quote', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/quote.json?symbol=${code}&extend=detail`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
});

// 高管信息
router.get('/:code/skholder', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/f10/cn/skholder.json?symbol=${code}`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: { items: [] } };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    datas: json.data.items
  };
});

// 十大股东
router.get('/:code/topholder', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let url = `https://stock.xueqiu.com/v5/stock/f10/cn/top_holders.json?symbol=${code}&circula=0`;

  if (ctx.request.query.start) {
    url += `&locate=${ctx.request.query.start}&start=${ctx.request.query.start}`
  } else {
    url += '&count=200';
  }

  let rs = await httpClient.get(url, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
});

// 分红
router.get('/:code/bonus', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/f10/cn/bonus.json?symbol=${code}&size=100&page=1&extend=true`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
});

// 利润表
router.get('/:code/income', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let type = ctx.request.query.type || 'all';

  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/finance/cn/income.json?symbol=${code}&type=${type}&is_detail=true&count=100`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
});

// 主要指标
router.get('/:code/indicator', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/finance/cn/indicator.json?symbol=${code}&type=all&is_detail=true&count=60`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
});

// 板块所属股票涨跌情况
router.get('/:code/stock', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs2 = await httpClient.get(`https://stock.xueqiu.com/v5/stock/quote.json?symbol=${code}&extend=detail`, xueQiuRequestOptions);
  let json2 = JSON.parse(rs2.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json2.data
  };
});

// 板块所属股票涨跌情况
router.get('/:code/stocks', async (ctx, next) => {
  await syncXueQiuCookies();

  let code = ctx.params.code;
  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/forum/stocks.json?ind_code=${code}`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: { items: [] } };
  let codes = json.data.items.map(i => i.symbol).join('%2C');

  let rs2 = await httpClient.get(`https://stock.xueqiu.com/v5/stock/batch/quote.json?symbol=${codes}&extend=detail`, xueQiuRequestOptions);
  let json2 = JSON.parse(rs2.body) || { data: {} };

  ctx.body = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json2.data
  };
});

// 当日交易
router.get('/:code/chartdatas', async (ctx, next) => {
  let rs = await getChartDatas(ctx.params.code);

  ctx.body = rs;
});

router.get('/daily/profit/current', async (ctx) => {
  let rs = await ctx.getDbHelper(0).queryForList(scripts.GetCurrentProfits);

  ctx.body = rs;
}, '获取当前收益信息');

router.get('/daily/profit/totals', async (ctx) => {
  let rs = await ctx.getDbHelper(0).queryForList(scripts.GetDailyProfitTotals);

  ctx.body = rs;
}, '获取每日收益总额');

router.get('/daily/profit/:code', async (ctx) => {
  let rs = await ctx.getDbHelper(0).queryForList(scripts.GetDailyProfits, { code: ctx.params.code });

  ctx.body = rs;
}, '获取每日收益信息');

async function getChartDatas (code) {
  await syncXueQiuCookies();

  let rs = await httpClient.get(`https://stock.xueqiu.com/v5/stock/history/trade.json?symbol=${code}&count=200`, xueQiuRequestOptions);

  let json = JSON.parse(rs.body) || { data: { items: [] } };

  return {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true,
    data: json.data
  };
}

async function syncXueQiuCookies () {
  if (expireTimes != 0 && (expireTimes - new Date().getTime()) / 1000 / 60 < 6000) {
    return;
  }

  let rs = await httpClient.get('https://xueqiu.com/snowman/account/login');

  let cookies = rs.headers['set-cookie'];

  (cookies || []).forEach(item => {
    if (item.startsWith('xq_a_token')) {
      expireTimes = new Date().getTime();
      xueQiuRequestOptions.headers.Cookie = item.substring(0, item.indexOf(';'));
    }
  });
};

/**
 * 收集已关注的股票信息
 */
async function collectDatas () {
  let shares = await getDbHelper(0).queryForList(scripts.GetShares);

  if (shares.success && shares.datas.length > 0) {
    for (let d of shares.datas) {
      await collectShare(d.Code, d.Name);
    }
  }
}

/**
 * 收集股票信息
 * @param {*} code 股票代号 
 * @param {*} name 股票名称
 */
async function collectShare (code, name) {
  let data = await getShareInfomation(code, name);

  if (data.currentPrice > 0) {
    await getDbHelper(0).execute(scripts.SaveDailyDatas, data);
  }
}

/**
 * 收集股票指数信息
 */
async function collectIndexes () {
  let sh = getShareIndex('s_sh000001', '上证指数');
  let sz = getShareIndex('s_sz399001', '深圳成指');
  let cy = getShareIndex('s_sz399006', '创业板指');

  let rs = {
    at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    success: true
  };

  await Promise.all([sh, sz, cy]).then(values => {
    values.forEach(val => {
      getDbHelper(0).execute(scripts.SaveIndex, {
        name: val.name,
        recordDateTime: rs.at,
        index: val.index,
        changes: val.changes,
        changeRatio: val.changeRatio,
        turnoverVolume: val.turnoverVolume
      });
    });

    ctx.body = rs;
  }).catch(err => {
    rs.success = false;
    rs.message = err.message;

    ctx.body = rs;
  });
}

/**
 * 获取股票详细信息
 * @param {*} code 股票代码
 * @param {*} name 股票名称
 * @returns 股票详细信息
 */
async function getShareInfomation (code, name) {
  let rs = await httpClient.get(`http://qt.gtimg.cn/q=${code}`, requestOptions);

  let body = (rs.body || '');
  let content = body.substring(body.indexOf('"') + 1, body.lastIndexOf('"'));
  let items = content.split('~');

  let date = items[30];

  return {
    code: code,
    date: `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`,
    time: `${date.substring(8, 10)}:${date.substring(10, 12)}:${date.substring(12, 14)}`,
    name: name,
    startPrice: items[5],
    yesterdayPrice: items[4],
    currentPrice: items[3],
    maxPrice: items[33],
    minPrice: items[34],
    salleCounts: items[36],
    salleAmount: items[37]
  };
}

/**
 * 获取股票指数信息
 * @param {*} code 指数代码 
 * @param {*} name 指数名称
 * @returns 指数详情
 */
async function getShareIndex (code, name) {
  let rs = await httpClient.get(`http://qt.gtimg.cn/q=${code}`, requestOptions);

  let body = (rs.body || '');
  let content = body.substring(body.indexOf('"') + 1, body.lastIndexOf('"'));
  let items = content.split('~');

  return {
    code: code,
    name: name,
    index: items[3],
    changes: items[4],
    changeRatio: items[5],
    turnoverVolume: items[7],
    turnoverAmount: items[8]
  };
}

setInterval(() => {
  let now = new Date();
  let week = now.getDay();
  let hours = now.getHours();
  let minutes = now.getMinutes();

  if (week == 0 || week > 5) {
    return;
  }

  // 休市处理
  if (hours < 9 || hours > 15) {
    return;
  }

  // 早、晚间休市细化处理
  if ((hours == 9 && minutes < 15) || (hours == 15 && minutes > 5)) {
    return;
  }

  // 午间休市暂停
  if (hours == 12 || (hours == 11 && minutes > 30)) {
    return;
  }

  collectDatas().then(rs => { }).catch(err => { });
  collectIndexes().then(rs => { }).catch(err => { });
}, 5 * 1000);

module.exports = router;